package com.jacen.etl.util;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import jodd.util.StringUtil;

public class SqlCondition{
  private StringBuilder sb = new StringBuilder(" ");
  private List<Object> params = new ArrayList<Object>();

  public String getCondition()
  {
    return this.sb.toString();
  }

  public List<Object> getParams()
  {
    return this.params;
  }

  public SqlCondition and() {
    this.sb.append(" and ");
    return this;
  }

  public SqlCondition or() {
    this.sb.append(" or ");
    return this;
  }

  public SqlCondition equal(String column, Object value)
  {
    checkParam(column, value);
    this.sb.append(column).append(" = ? ");
    this.params.add(value);
    return this;
  }

  public SqlCondition equal(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return equal(column, value);
  }

  public SqlCondition notEqual(String column, Object value)
  {
    checkParam(column, value);
    this.sb.append(column).append(" != ? ");
    this.params.add(value);
    return this;
  }

  public SqlCondition notEqual(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return notEqual(column, value);
  }

  public SqlCondition gt(String column, Object value)
  {
    checkParam(column, value);
    if ((value instanceof Date)) {
      this.sb.append(column).append(" > ").append(DBFeature.feature.toDate());
      this.params.add(DateUtils.date2Str((Date)value, "yyyy-MM-dd HH:mm:ss"));
    } else {
      this.sb.append(column).append(" > ? ");
      this.params.add(value);
    }

    return this;
  }

  public SqlCondition gt(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return gt(column, value);
  }

  public SqlCondition ge(String column, Object value)
  {
    checkParam(column, value);
    if ((value instanceof Date)) {
      this.sb.append(column).append(" >=  ").append(DBFeature.feature.toDate());
      this.params.add(DateUtils.date2Str((Date)value, "yyyy-MM-dd HH:mm:ss"));
    } else {
      this.sb.append(column).append(" >= ? ");
      this.params.add(value);
    }
    return this;
  }

  public SqlCondition ge(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return ge(column, value);
  }

  public SqlCondition lt(String column, Object value)
  {
    checkParam(column, value);
    if ((value instanceof Date)) {
      this.sb.append(column).append(" < ").append(DBFeature.feature.toDate());
      this.params.add(DateUtils.date2Str((Date)value, "yyyy-MM-dd HH:mm:ss"));
    } else {
      this.sb.append(column).append(" < ? ");
      this.params.add(value);
    }
    return this;
  }

  public SqlCondition lt(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return lt(column, value);
  }

  public SqlCondition le(String column, Object value)
  {
    checkParam(column, value);
    if ((value instanceof Date)) {
      this.sb.append(column).append(" <= ").append(DBFeature.feature.toDate());
      this.params.add(DateUtils.date2Str((Date)value, "yyyy-MM-dd HH:mm:ss"));
    } else {
      this.sb.append(column).append(" <= ? ");
      this.params.add(value);
    }
    return this;
  }

  public SqlCondition le(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return le(column, value);
  }

  public SqlCondition like(String column, Object value) {
    checkParam(column, value);
    this.sb.append(column).append(" like ? ");
    this.params.add("%" + value + "%");
    return this;
  }

  public SqlCondition like(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return like(column, value);
  }

  public SqlCondition llike(String column, Object value) {
    checkParam(column, value);
    this.sb.append(column).append(" like ? ");
    this.params.add("%" + value);
    return this;
  }

  public SqlCondition llike(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return llike(column, value);
  }

  public SqlCondition rlike(String column, Object value) {
    checkParam(column, value);
    this.sb.append(column).append(" like ? ");
    this.params.add(value + "%");
    return this;
  }

  public SqlCondition rlike(String column, Object value, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return rlike(column, value);
  }

  public SqlCondition between(String column, Object value1, Object value2) {
    checkBetween(column, value1, value2);

    if (((value1 instanceof Timestamp)) || ((value1 instanceof Date)))
      this.sb.append(column).append(" between ").append(DBFeature.feature.toDate()).append(" and ").append(DBFeature.feature.toDate());
    else {
      this.sb.append(column).append(" between ? and ? ");
    }
    if ((value1 instanceof Date)) value1 = DateUtils.date2Str((Date)value1, "yyyy-MM-dd HH:mm:ss");
    if ((value2 instanceof Date)) value2 = DateUtils.date2Str((Date)value2, "yyyy-MM-dd HH:mm:ss");

    this.params.add(value1);
    this.params.add(value2);
    return this;
  }

  public SqlCondition between(String column, Object value1, Object value2, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return between(column, value1, value2);
  }

  public SqlCondition notBetween(String column, Object value1, Object value2) {
    checkBetween(column, value1, value2);

    if (((value1 instanceof Timestamp)) || ((value1 instanceof Date)))
      this.sb.append(column).append(" not between ").append(DBFeature.feature.toDate()).append(" and ").append(DBFeature.feature.toDate());
    else {
      this.sb.append(column).append(" not between ? and ? ");
    }
    if ((value1 instanceof Date)) value1 = DateUtils.date2Str((Date)value1, "yyyy-MM-dd HH:mm:ss");
    if ((value2 instanceof Date)) value2 = DateUtils.date2Str((Date)value2, "yyyy-MM-dd HH:mm:ss");

    this.params.add(value1);
    this.params.add(value2);
    return this;
  }

  public SqlCondition notBetween(String column, Object value1, Object value2, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return notBetween(column, value1, value2);
  }

  public SqlCondition isNull(String column) {
    if (StringUtil.isEmpty(column)) throw new RuntimeException("列字段为空");
    this.sb.append(column).append(" is null ");
    return this;
  }

  public SqlCondition isNull(String column, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return isNull(column);
  }

  public SqlCondition isNotNull(String column) {
    if (StringUtil.isEmpty(column)) throw new RuntimeException("列字段为空");
    this.sb.append(column).append(" is not null ");
    return this;
  }

  public SqlCondition isNotNull(String column, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return isNotNull(column);
  }

  public SqlCondition in(String column, List<? extends Object> objs) {
    if (StringUtil.isEmpty(column)) throw new RuntimeException("列字段为空");
    if (objs == null) throw new RuntimeException("objs值为null");

    this.sb.append(column).append(" in ( ");
    for (int i = 0; i < objs.size(); i++) {
      this.sb.append("?");
      if (i == objs.size() - 1) continue; this.sb.append(", ");
    }
    this.sb.append(") ");

    this.params.addAll(objs);
    return this;
  }

  public SqlCondition in(String column, List<? extends Object> objs, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return in(column, objs);
  }

  public SqlCondition notIn(String column, List<? extends Object> objs) {
    if (StringUtil.isEmpty(column)) throw new RuntimeException("列字段为空");
    if (objs == null) throw new RuntimeException("objs值为null");

    this.sb.append(column).append(" not in ( ");
    for (int i = 0; i < objs.size(); i++) {
      this.sb.append("?");
      if (i == objs.size() - 1) continue; this.sb.append(", ");
    }
    this.sb.append(") ");

    this.params.addAll(objs);
    return this;
  }

  public SqlCondition notIn(String column, List<? extends Object> objs, String prefix) {
    if (StringUtil.isEmpty(prefix)) this.sb.append(""); else
      this.sb.append(prefix);
    return notIn(column, objs);
  }

  private void checkParam(String column, Object value) {
    if (StringUtil.isEmpty(column)) throw new RuntimeException("列字段为空");
    if (value == null) throw new RuntimeException("value值为null"); 
  }

  private void checkBetween(String column, Object value1, Object value2)
  {
    if (StringUtil.isEmpty(column)) throw new RuntimeException("列字段为空");
    if (value1 == null) throw new RuntimeException("value1值为null");
    if (value2 == null) throw new RuntimeException("value2值为null");
    if (((value1 instanceof Date)) && (!(value2 instanceof Date)))
      throw new RuntimeException("value1和value2必须同时为日期类型");
    if (((value2 instanceof Date)) && (!(value1 instanceof Date)))
      throw new RuntimeException("value1和value2必须同时为日期类型");
  }
}